(defproto bubble-graph-overlay-proto '(bubbles) ()  graph-overlay-proto)

(defmeth  bubble-graph-overlay-proto :bubbles
  (&optional (bubbles nil set))
  "list of bubble objects"
  (if set (setf (slot-value 'bubbles) bubbles))
  (slot-value 'bubbles))

(defproto bubble-proto '(coord color state selection fill))

     (defmeth bubble-proto :coord
      (&optional (coord nil set))
       "coords of bubble"
       (if set (setf (slot-value 'coord) coord))
      (slot-value 'coord))

(defmeth bubble-proto :color
      (&optional (color nil set))
       "colors of bubble"
       (if set (setf (slot-value 'color) color))
      (slot-value 'color))

(defmeth bubble-proto :state
      (&optional (state nil set))
       "states of bubble"
       (if set (setf (slot-value 'state) state))
      (slot-value 'state))


(defmeth bubble-proto :selection
      (&optional (selection nil set))
       "selection of bubble"
       (if set (setf (slot-value 'selection) selection))
      (slot-value 'selection))

(defmeth bubble-proto :fill
  (&optional (fill nil set))
  "frame or filled bubble"
  (if set (setf (slot-value 'fill) fill))
  (slot-value 'fill))


(defmeth bubble-proto :draw (graph point)
  (let* ((x1 (first (send self :coord)))
         (y1 (second (send self :coord)))
         (width (third (send self :coord)))
         (height (fourth (send self :coord)))
         (point point)
         (mask-color (send graph :back-color))
         )
       (when (send self :fill) 
             (send graph :draw-color (send self :color))               
             (send graph :paint-oval x1 y1 width height))
    (send graph :line-width 2)
    (send graph :draw-color mask-color)
     (send graph :frame-oval x1 y1 width height)
    (send graph :line-width 1)
    (when (not (equal (send graph :point-state point) 'invisible))
         ; (send graph :line-width 2)
          ;(send graph :draw-color mask-color)
         ; (send graph :draw-color (send self :color)) 
          ;(if (send graph :point-selected point) 
           ;   (send graph :paint-oval x1 y1 width height)
            ;  (send graph :frame-oval x1 y1 width height))

          (if (or (send graph :point-selected point) 
                  (equal (send graph :point-state point) 'hilited))
             (send graph :line-width 2)
             (send graph :line-width 1))
          (send graph :draw-color (send graph :point-color point))
          ;(if (send graph :point-selected point) 
             ; (send graph :draw-color 'black)
             ; (send graph :draw-color (send graph :point-color point))
            ;  )
         (send graph :frame-oval x1 y1 width height)
         )
    (send graph :draw-color 'black)
    (send graph :line-width 1)))



(defun bubble-biplot (z &rest args)
  (let ((plot (apply #'scatterplot args))
        (prop z)
        )
    

    (defmeth plot :add-overlay-bubbles (&key prop (colour 'blue) (oval nil) (fill nil))
      (let ((overlay-bubbles (send bubble-graph-overlay-proto :new)))

        
        (send self :add-overlay overlay-bubbles)

   
   
        (defmeth plot :redraw-content ()
          (call-next-method)
          (send overlay-bubbles :redraw))


        (defmeth plot :adjust-screen-point (point)
          (call-next-method point)
          (when (< point (send self :num-points))
                (send (select (send overlay-bubbles :bubbles) point) :draw self point)))



        (defmeth plot :do-click (x y m n)
          (call-next-method x y m n)
          (send self :redraw))

        (defmeth plot :new-plot (&rest args)
          (call-next-method args)
          (send overlay-bubbles :compute-coords)
          (send self :redraw)
          )

        (defmeth overlay-bubbles :compute-coords ()
          (let* (
                 (graph (send self :graph))
                 (colour (if colour colour 'blue))
                 (oval oval) ;controls if it prints ovals when the plot is not square
                 (variable1 (first (send graph :current-variables)))
                 (variable2 (second (send graph :current-variables)))
                 (x (send graph :point-coordinate 
                           variable1
                          (iseq (send graph :num-points))))
                 (prop (coerce (if prop (coerce prop 'list) (repeat 1 (length x))) 'vector))
                 (range-prop (abs (- (max prop) (min prop))))
                 (z-prop (if (and (variance prop) 
                                  (and (or (< (min prop) 0) (> (max prop) 1))
                                       (> range-prop 1))) ;has to be between 0 1
                             (/ (+ prop (if (< (min prop) 0)
                                            (abs (min prop))
                                            (- (min prop)))) range-prop)
                             (+ prop (if (< (min prop) 0)
                                            (abs (min prop))
                                            (- (min prop))))))
                 (prop (if (variancep prop) 
                           (+  0.5 z-prop)
                           (if (< (min prop) 0) (+ (abs (min prop))) prop)))
                 (y (send graph :point-coordinate 
                          variable2 
                          (iseq (send graph :num-points))))
                 (rangex (apply 'send graph :real-to-canvas (send graph :range variable1)))
                 (rangey (apply 'send graph :real-to-canvas (send graph :range variable2)))
                 (size (send graph :size))
                 (sizex (round (/ (* (first size) 10) 250)))
                 (sizey (round (/ (* (second size ) 10) 250)))
                 ;  (old-bubbles (if (send self :bubbles) (send self :bubbles) nil))
                 (temp-sizex  (+ 1 (* prop sizex)))
                 (temp-sizey (+ 1 (* prop sizey)))
                 (temp-coord (column-list (apply 'bind-rows (mapcar #'(lambda (tempx tempy) 
                                         (send graph :real-to-canvas tempx tempy))
                                     x y))))
                 (x1 (round (- (first temp-coord) (/ temp-sizex 2))))
                 (y1 (round (- (second temp-coord) (/ temp-sizex 2))))
                 (x2 (round (+ (first temp-coord) (/ temp-sizex 2))))
                 (y2 (round (+ (second temp-coord) (/ temp-sizex 2))))
                 (width (coerce (round (abs (- x1 x2)))'list))
                 (height (coerce (round (abs (- y1 y2))) 'list))
                 (x1 (coerce x1 'list))
                 (y1 (coerce y1 'list))
                 (bubble-object-list 
                  (mapcar #'(lambda (x y w h) 
                              (let ((bu-p (send bubble-proto :new)))
                                (send bu-p :coord (list x y w h))
                                bu-p))
                          x1
                          y1
                          width height)))

            (mapcar #'(lambda (newbuble point)
                        (send newbuble :color (send graph :point-color point ))
                        (send newbuble :selection (send graph :point-selected point))
                        (send newbuble :state (send graph :point-state point)))
                    bubble-object-list (iseq (send graph :num-points)))

            (let ((any-fill (which (mapcar #'(lambda (buble) (send buble :fill))
                                           bubble-object-list))))
              (when any-fill
                    (send (send self :graph) :point-state 
                               any-fill
                          'invisible)))
            
            (send self :bubbles bubble-object-list)
            ))

        (defmeth plot :resize ()
          (call-next-method)
          (send overlay-bubbles :compute-coords))

                 
        (defmeth overlay-bubbles :redraw ()
          (let ((graph (send self :graph)))
            (send graph :start-buffering)
            (mapcar #'(lambda (bubble-object point)
                        (send bubble-object :draw graph point))
                    (send self :bubbles) (iseq (send graph :num-points)))
            (send graph :buffer-to-screen)
            ))
        ))
        (send plot :add-overlay-bubbles :prop prop)
       ; (send overlay-bubbles :compute-coords)
    (send plot :resize)
    (send plot :redraw)
    plot
    ))


